package com.handinglian.ai.netty.client.handler;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.handinglian.ai.callin.entity.CallIn;
import com.handinglian.ai.callin.entity.CallInBusiness;
import com.handinglian.ai.callin.entity.CallInChat;
import com.handinglian.ai.callin.enums.AiBusinessEnum;
import com.handinglian.ai.callin.enums.IsServiceEnum;
import com.handinglian.ai.callin.param.CallInCreateParam;
import com.handinglian.ai.callin.service.CallInBusinessService;
import com.handinglian.ai.callin.service.CallInChatService;
import com.handinglian.ai.callin.service.CallInService;
import com.handinglian.ai.common.component.SpringContextUtils;
import com.handinglian.ai.common.util.ChannelUtil;
import com.handinglian.ai.netty.client.GlobalConfig;
import com.handinglian.ai.netty.client.HeartbeatThread;
import com.handinglian.ai.netty.client.NettyClient;
import com.handinglian.ai.netty.request.ActionReqPacket;
import com.handinglian.ai.netty.request.PlayAndGetDtmfReqPacket;
import com.handinglian.ai.netty.response.EventRespPacket;
import com.handinglian.ai.thirdparty.constants.YyConstants;
import com.handinglian.ai.thirdparty.dto.RobotChatRespDto;
import com.handinglian.ai.thirdparty.enums.AITypeEnum;
import com.handinglian.ai.thirdparty.enums.ActionTypeEnum;
import com.handinglian.ai.thirdparty.enums.EventTypeEnum;
import com.handinglian.ai.thirdparty.service.BaiduAIService;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.EventLoop;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 读取服务器返回的响应信息
 */
@Slf4j
public class ClientHandler extends ChannelInboundHandlerAdapter {
    private BaiduAIService baiduAIService = SpringContextUtils.getBean(BaiduAIService.class);
    private NettyClient nettyClient = SpringContextUtils.getBean(NettyClient.class);
    private CallInService callInService = SpringContextUtils.getBean(CallInService.class);
    private CallInBusinessService callInBusinessService = SpringContextUtils.getBean(CallInBusinessService.class);
    private CallInChatService callInChatService = SpringContextUtils.getBean(CallInChatService.class);

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String body = (String) msg;
        EventRespPacket eventRespPacket = JSON.parseObject(body, EventRespPacket.class);
        EventRespPacket.EventBean event = eventRespPacket.getEvent();
        try {
            if (Objects.isNull(event)) {
                return;
            }
            String name = event.getName();
            String callid = event.getCallid();
            String data = event.getData();
            if (name.equals(EventTypeEnum.AUTH_OK.getKey())) {// 认证成功
                HeartbeatThread thread = new HeartbeatThread();
                thread.start();
            } else if (name.equals(EventTypeEnum.CONNECTED.getKey())) {
                connected(callid, data);
            } else if (name.equals(EventTypeEnum.SCENE_OVER.getKey())) {
                // 结束场景
                GlobalConfig.SCENE_MAP.put(callid, Integer.valueOf(event.getSceneid()));
            } else if (name.equals(EventTypeEnum.ASR_RESP.getKey())) {
                asrResp(callid, data, ctx);
            } else if (name.equals(EventTypeEnum.RECV_DTMF.getKey())) {
                recvDtmf(data, event.getVname(), callid);
            }
        } catch (Exception e) {
            log.error("异常json格式：" + body, e);
        }

    }

    /**
     * 识别用户DTMF按键
     */
    private void recvDtmf(String data, String vname, String callid) {
        if (vname.equals("dtmf_phone")) {
            //设置随路数据
            String reqStr = "{\"request\":{\"callid\":\"" + callid + "\",\"actions\":[{\"action\":\"setUuid\",\"data\":\"uui_phone:" + data + "\"}]}}";
            nettyClient.sendMsg(reqStr);
            reqStr = "{\"request\":{\"callid\":\"" + callid + "\",\"sceneid\":\"" + "4"
                    + "\",\"actions\":[{\"action\":\"ttsSay\",\"data\":\"您的手机号是" + data + "，现在开始给您转人工客服，请稍候！\"},{\"action\":\"transferQueue\",\"data\":\"001\"}]}}";
            nettyClient.sendMsg(reqStr);
        }
    }

    /**
     * 客户侧识别的文本
     */
    private void asrResp(String callid, String data, ChannelHandlerContext ctx) {
        if (StrUtil.isBlank(data)){
            return;
        }

        ActionReqPacket actionReqPacket ;
        Integer sceneid = GlobalConfig.SCENE_MAP.get(callid)+1;
        GlobalConfig.SCENE_MAP.put(callid, sceneid);

        //转人工服务
        boolean manualFlag = (data.contains("转")||data.contains("换"))&&data.contains("人工");
        if (manualFlag){
            actionReqPacket = getActionReqPacket(callid, sceneid.toString(), ActionTypeEnum.TTS_SAY.getKey(), "正早为您转接人工服务！");
            ActionReqPacket action = getActionReqPacket(callid, sceneid.toString(), ActionTypeEnum.TRANSFER_QUEUE.getKey(), "001");
            actionReqPacket.getRequest().getActions().add(action.getRequest().getActions().get(0));
            nettyClient.sendMsg(actionReqPacket);
            callInChat(callid, "转人工", IsServiceEnum.MASS.getKey());
            return;
        }
        callInChat(callid, data, IsServiceEnum.MASS.getKey());

        String sessionId = GlobalConfig.SESSION_ID_MAP.get(callid);
        sessionId = StrUtil.isBlank(sessionId) ? "" : sessionId;

        RobotChatRespDto robotChatRespDto = null;
        try {
            robotChatRespDto = baiduAIService.getRobotIntention(data, sessionId);
        } catch (Exception e){
            e.printStackTrace();
        }
        if (Objects.isNull(robotChatRespDto)){
            actionReqPacket = getFailureActionReqPacket(callid, sceneid.toString());
            nettyClient.sendMsg(actionReqPacket);
            return;
        }
        String content = null;
        String type = null;
        List<RobotChatRespDto.ResultBean.ResponseListBean> responseBeans = robotChatRespDto.getResult().getResponse_list();
        for (RobotChatRespDto.ResultBean.ResponseListBean responseBean : responseBeans){
            for (RobotChatRespDto.ResultBean.ResponseListBean.ActionListBean action : responseBean.getAction_list()) {
                //筛选正确的回复内容
                Boolean flag = action.getType().equals(AITypeEnum.SATISFY.getKey())
                        || action.getType().equals(AITypeEnum.CLARIFY.getKey());
                if (flag) {
                    content = action.getSay()+"请问还需要咨询哪些内容。";
                    type = action.getType();
                    break;
                }
            }

            if (StrUtil.isNotBlank(content)){
                break;
            }
        }

        String intent = "";
        for (RobotChatRespDto.ResultBean.ResponseListBean responseBean : responseBeans){
            intent = responseBean.getSchema().getIntent();
            if (StrUtil.isNotBlank(intent)){
                break;
            }
        }
        AiBusinessEnum aiBusinessEnum = AiBusinessEnum.valueOfKey(intent);
        if (Objects.nonNull(aiBusinessEnum)){
            callInBusiness(callid, aiBusinessEnum.getDescription());
        }


        if (StrUtil.isBlank(content)) {
            type = AITypeEnum.FAILURE.getKey();
        }

        //设置sessionId
        if (StrUtil.isBlank(sessionId)) {
            sessionId = robotChatRespDto.getResult().getSession_id();
            GlobalConfig.SESSION_ID_MAP.put(callid, sessionId);
        }

        if (type.equals(AITypeEnum.SATISFY.getKey())) {
            GlobalConfig.SESSION_ID_MAP.remove(callid);
            actionReqPacket = getActionReqPacket(callid, sceneid.toString(), ActionTypeEnum.TTS_SAY.getKey(), content);
        } else if (type.equals(AITypeEnum.FAILURE.getKey())) {
            actionReqPacket = getFailureActionReqPacket(callid, sceneid.toString());
        } else {
            actionReqPacket = getActionReqPacket(callid, sceneid.toString(), ActionTypeEnum.TTS_SAY.getKey(), content);
        }
        nettyClient.sendMsg(actionReqPacket);
        callInChat(callid, actionReqPacket.getRequest().getActions().get(0).getData(), IsServiceEnum.SERVICE.getKey());
    }

    /**
     * 客户触发AI场景
     */
    private void connected(String callid, String data) {
        GlobalConfig.SCENE_MAP.put(callid, 0);
        GlobalConfig.ERROR_COUNT.put(callid, 0);
        String content = "您好，洞桥智能语音客服为您服务，请说出您要咨询的业务";
        ActionReqPacket actionReqPacket = getActionReqPacket(callid, "1", ActionTypeEnum.TTS_SAY.getKey(), content);
        nettyClient.sendMsg(actionReqPacket);

        callInAi(callid,data);
        callInChat(callid, content, IsServiceEnum.SERVICE.getKey());
    }

    private void callInAi(String callid, String data){
        CallIn callIn = new CallIn();
        callIn.setCallerNo(data);
        callIn.setCallid(callid);
        callIn.setCreateTime(new Date());
        callInService.create(callIn);
    }

    private void callInBusiness(String callid, String business){
        CallInBusiness callInBusiness = new CallInBusiness();
        callInBusiness.setCallid(callid);
        callInBusiness.setBusiness(business);
        callInBusiness.setCreateTime(new Date());
        callInBusinessService.create(callInBusiness);
    }

    private void callInChat(String callid, String content, Integer isService){
        CallInChat callInChat = new CallInChat();
        callInChat.setCallid(callid);
        callInChat.setContent(content);
        callInChat.setIsService(isService);
        callInChat.setCreateTime(new Date());
        callInChatService.create(callInChat);
    }

    private ActionReqPacket getActionReqPacket(String callid, String sceneid, String action, String data) {
        ActionReqPacket actionReqPacket = new ActionReqPacket();
        ActionReqPacket.RequestBean requestBean = new ActionReqPacket.RequestBean();
        requestBean.setCallid(callid);
        requestBean.setSceneid(sceneid);
        ActionReqPacket.RequestBean.ActionsBean actionsBean = new ActionReqPacket.RequestBean.ActionsBean();
        actionsBean.setData(data);
        actionsBean.setAction(action);
        requestBean.getActions().add(actionsBean);
        actionReqPacket.setRequest(requestBean);
        return actionReqPacket;
    }

    private ActionReqPacket getFailureActionReqPacket(String callid, String sceneid) {
        Integer count = GlobalConfig.ERROR_COUNT.get(callid);
        count = count+1;
        GlobalConfig.ERROR_COUNT.put(callid,count);

        ActionReqPacket actionReqPacket = new ActionReqPacket();
        ActionReqPacket.RequestBean requestBean = new ActionReqPacket.RequestBean();
        ActionReqPacket.RequestBean.ActionsBean actionsBean = new ActionReqPacket.RequestBean.ActionsBean();
        if (count < 2){
            requestBean.setCallid(callid);
            requestBean.setSceneid(sceneid);
            actionsBean.setData("没有听清楚提问，请重复问题！");
            actionsBean.setAction(ActionTypeEnum.TTS_SAY.getKey());
            requestBean.getActions().add(actionsBean);
            actionReqPacket.setRequest(requestBean);
        } else {
            requestBean.setCallid(callid);
            requestBean.setSceneid(sceneid);
            actionsBean.setData("我不知道应该怎么答复您。正在为您转按键服务");
            actionsBean.setAction(ActionTypeEnum.TTS_SAY.getKey());
            requestBean.getActions().add(actionsBean);
            actionReqPacket.setRequest(requestBean);

            ActionReqPacket action = getActionReqPacket(callid, sceneid, ActionTypeEnum.TRANSFER_IVR.getKey(), YyConstants.IVR);
            actionReqPacket.getRequest().getActions().add(action.getRequest().getActions().get(0));
        }
        return actionReqPacket;
    }

    private String getFailureContent(Integer sceneId){
        if (sceneId.equals(1)){
            return "没有听清楚提问，请重复问题！";
        } else {
            return "我不知道应该怎么答复您。正在为您转按键服务";
        }
    }

    private PlayAndGetDtmfReqPacket getPlayAndGetDtmfPacket(String callid, String sceneid, String action, String data, String type, String vname, String length, String terminal) {
        PlayAndGetDtmfReqPacket playAndGetDtmfReqPacket = new PlayAndGetDtmfReqPacket();
        PlayAndGetDtmfReqPacket.RequestBean requestBean = new PlayAndGetDtmfReqPacket.RequestBean();
        requestBean.setCallid(callid);
        requestBean.setSceneid(sceneid);
        PlayAndGetDtmfReqPacket.RequestBean.ActionsBean actionsBean = new PlayAndGetDtmfReqPacket.RequestBean.ActionsBean();
        actionsBean.setData(data);
        actionsBean.setAction(action);
        actionsBean.setType(type);
        actionsBean.setLength(length);
        actionsBean.setTerminal(terminal);
        actionsBean.setVname(vname);
        requestBean.getActions().add(actionsBean);
        playAndGetDtmfReqPacket.setRequest(requestBean);
        return playAndGetDtmfReqPacket;
    }

    // 数据读取完毕的处理
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        // System.out.println("客户端读取数据完毕");
    }


    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.error("连接断线！！");
        //如果运行过程中服务端挂了,执行重连机制
        EventLoop eventLoop = ctx.channel().eventLoop();
        eventLoop.schedule(() -> nettyClient.start(), 10L, TimeUnit.SECONDS);
        super.channelInactive(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("client 读取数据出现异常：",cause.getMessage());
        ctx.channel().close();
    }

}
